package com.rengwuxian.coursecoroutines._3_scope_context

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.job
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.coroutines.EmptyCoroutineContext

/**
 * GlobalScope
 * GlobalScope、CoroutineScope、Job
 *
 * 特殊的CoroutineScope：GlobalScope：单例的CoroutineScope，可以直接启动协程。（容易用错,是一个DelicateCoroutineApi）
 * 特点：没有内置Job对象，它的coroutineContext也是EmptyCoroutineContext的。
 *      当调用GlobalScope.coroutineContext.job（非空类型的扩展属性）时，会抛出一个异常，因为没有。
 * 源码：
 * public val CoroutineContext.job: Job get() = get(Job) ?: error("Current context doesn't contain Job in it: $this")
 * 该代码唯一会抛异常的情况，就是GlobalScope获取job的时候。
 *
 * 由GlobalScope启动的协程是没有父协程的，全局的，协程间没有任何关联，不和任何组件的生命周期绑定。
 * 下方代码log打印：
 * job parent: null
 *
 * GlobalScope.launch {} 和 CoroutineScope（EmptyCoroutineContext）.launch{} 启动协程的效果是一样的。
 * 启动的协程没有跟任何父Job绑定，所以不会被任何组件的关闭而自动取消协程（有造成资源浪费的风险，仅此而已）
 * 弄懂上面，大胆用，只要做好资源的管理，及时关闭协程，不是不用。
 *
 * GlobalScope.cancel() : Scope cannot be cancelled because it does not have a job(不能调用)
 *
 * GlobalScope.async内部协程如果异常，会被吞掉，除非await有人调用，会抛到await那个协程所在的协程树中。
 */
@OptIn(DelicateCoroutinesApi::class)
fun main() = runBlocking<Unit> {
  CoroutineScope(EmptyCoroutineContext).launch {

  }
  GlobalScope.launch {

  }
  GlobalScope.launch {

  }
  var job : Job? = null
//  GlobalScope.cancel()
  job = GlobalScope.launch {
    coroutineContext.job
    launch {
      println("Child launch start...")
      delay(3000)
      println("child launch end....")
    }
    launch {
      delay(100)
//      throw RuntimeException("Error!")
      job?.cancel()
    }
    delay(5000)
    println("launch end...")
  }
//  job.await()
  println("job parent: ${job.parent}")
  delay(10000)
}